package com.block.risk.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.block.common.model.dto.CountInfoDTO;
import com.block.common.service.ICountCommonService;
import com.block.common.service.LogFactory;
import com.block.db.entity.MemberExtInfo;
import com.block.db.entity.RiskBaseInfo;
import com.block.db.entity.RiskConfigInfo;
import com.block.db.entity.RiskResultInfo;
import com.block.db.mapper.RiskConfigInfoMapper;
import com.block.db.mapper.RiskResultInfoMapper;
import com.block.risk.constant.RiskConstant;
import com.block.risk.enums.ReqActionEnum;
import com.block.risk.model.result.RiskControlResult;
import com.block.risk.model.result.RiskJudgeResult;
import com.block.risk.service.IRiskCostRecordInfoService;
import com.block.risk.service.IRiskResultInfoService;
import com.block.risk.util.XinYanAesUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 
 * @since 2023-05-11
 */
@Service
public class RiskResultInfoServiceImpl extends ServiceImpl<RiskResultInfoMapper, RiskResultInfo> implements IRiskResultInfoService {

    private static Logger log = LogFactory.getRiskLog();

    @Resource
    RiskConfigInfoMapper riskConfigInfoMapper;
    @Autowired
    IRiskCostRecordInfoService riskCostRecordInfoService;
    @Autowired
    ICountCommonService countCommonService;

    @Override
    public RiskResultInfo getCommonRiskResult(MemberExtInfo memberExtInfo, RiskBaseInfo riskBaseInfo){

        if (StrUtil.hasEmpty(memberExtInfo.getUsername(), memberExtInfo.getMobile(), memberExtInfo.getIdCard())){
            log.info("【任信花风控查询】三要素信息不全【uid】{}", memberExtInfo.getUid());
            return null;
        }

        RiskResultInfo riskResultInfo = this.baseMapper.getEntityByDataIdAndTypeAndUid(String.valueOf(riskBaseInfo.getDataId()), riskBaseInfo.getDataType(), memberExtInfo.getUid());
        if (ObjectUtil.isEmpty(riskResultInfo)){
            try {
                riskResultInfo = this.getRiskHttpResult(memberExtInfo, riskBaseInfo);
                log.info("【任信花风控查询】风控结果【uid】{}", JSON.toJSONString(riskResultInfo));
            }catch (Exception exception){
                log.info(StrUtil.format("【任信花风控查询】查询结果异常【uid】{}", memberExtInfo.getUid()),  exception);
            }

            if (ObjectUtil.isEmpty(riskResultInfo)){
                log.info("【任信花风控查询】风控结果为空【uid】{}", memberExtInfo.getUid());
                return null;
            }
        }
        return riskResultInfo;
    }

    /**
     * 请求风控信息
     * @param memberExtInfo
     * @return
     */
    private RiskResultInfo getRiskHttpResult(MemberExtInfo memberExtInfo, RiskBaseInfo riskBaseInfo){

        String dateInfo = LocalDate.now().toString();

        RiskConfigInfo riskConfigInfo = riskConfigInfoMapper.selectById(riskBaseInfo.getConfigId());
        RiskResultInfo riskResultInfo = this.saveRiskResultInfo(riskBaseInfo, memberExtInfo);

        String outChannelArray = riskConfigInfo.getOutChannelArray();
        List<String> outChannelList = JSON.parseArray(outChannelArray, String.class);
        if (CollUtil.isNotEmpty(outChannelList) && outChannelList.contains(memberExtInfo.getChannelCode())){
            log.info("【任信花风控查询】不可风控渠道【outChannelList】{}", JSON.toJSONString(outChannelList));
            RiskResultInfo updateEntity = new RiskResultInfo();
            updateEntity.setId(riskResultInfo.getId());
            updateEntity.setCode("999");
            updateEntity.setMessage("渠道不过风控：" + memberExtInfo.getChannelCode());
            boolean update = this.updateById(updateEntity);
            return null;
        }

        if (ObjectUtil.isEmpty(riskResultInfo)){
            riskCostRecordInfoService.saveOrUpdateCostRecordInfo(dateInfo, ReqActionEnum.INIT, riskConfigInfo);
            return null;
        }

        // 查询该数据的结果
        String requestUrl = riskConfigInfo.getRequestUrl();
        String timestamp = String.valueOf(System.currentTimeMillis());
        String approveUrl = StrUtil.format(
                riskConfigInfo.getApproveUrl(),
                riskResultInfo.getId(),
                SecureUtil.md5(riskResultInfo.getMobile()).toLowerCase()
        );
        String orderNo = RandomUtil.randomString(28);

        Map<String, String> bizMap = new HashMap<>();
        bizMap.put("mobile", memberExtInfo.getMobile());
        bizMap.put("cert_name", memberExtInfo.getUsername());
        bizMap.put("cert_no", memberExtInfo.getIdCard());

        String key = riskConfigInfo.getAppSecret();
        String iv = riskConfigInfo.getAppKey().substring(0, 16);
        String decryptStr = XinYanAesUtils.encrypt(key, iv, JSON.toJSONString(bizMap));

        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("member_id", riskConfigInfo.getAppCode());
        paramMap.put("timestamp", timestamp);
        paramMap.put("trans_id", orderNo);
        paramMap.put("accessoryUrl", approveUrl);
        paramMap.put("data", decryptStr);

        log.info("【任信花风控】【风控数据查询】全景【requestUrl】{}【paramMap】{}【bizMap】{}", requestUrl, JSON.toJSONString(paramMap), JSON.toJSONString(bizMap));
        String response = HttpUtil.createPost(requestUrl)
                .header("Content-Type", "application/json")
                .body(JSON.toJSONString(paramMap))
                .execute().body();
        log.info("【任信花风控】【风控数据查询】全景结束【response】{}", response);

        JSONObject jsonObject = JSON.parseObject(response);
        String code = jsonObject.getString("code");
        String data = jsonObject.getString("data");
        String message = jsonObject.getString("msg");

        RiskResultInfo updateEntity = new RiskResultInfo();
        updateEntity.setId(riskResultInfo.getId());
        updateEntity.setCode(code);
        updateEntity.setMessage(message);
        updateEntity.setParamInfo(JSON.toJSONString(paramMap));
        updateEntity.setResultInfo(response);

        if (StrUtil.equals(code, "0")){
            String result = XinYanAesUtils.decrypt(key, iv, data);
            log.info("【任信花风控】数据解密结果【result】{}", result);
            updateEntity.setResult(result);
//            updateEntity.setStatus(0);
            /**
             * 是否收费
             */
            JSONObject dataObject = JSON.parseObject(result);
            String fee = dataObject.getString("fee");
            if (StrUtil.equals(fee, "Y")){
                updateEntity.setChargeFlag(RiskConstant.CHARGE_TYPE_COST);
                riskCostRecordInfoService.saveOrUpdateCostRecordInfo(dateInfo, ReqActionEnum.COST, riskConfigInfo);
            }else{
                updateEntity.setChargeFlag(RiskConstant.CHARGE_TYPE_FREE);
                riskCostRecordInfoService.saveOrUpdateCostRecordInfo(dateInfo, ReqActionEnum.FREE, riskConfigInfo);
            }

            //
            CountInfoDTO countInfoDTO = new CountInfoDTO(memberExtInfo.getChannelCode());
            countInfoDTO.setRiskRequestNumber(1);
            RiskControlResult controlResult = this.getRiskResult(dataObject);
            if (controlResult.isSuccess()){
//                countInfoDTO.setRiskSuccessNumber(1);
                updateEntity.setStatus(1);
            }
            countCommonService.calculateDataInfo2(countInfoDTO);

            // 更新风控结果信息
            updateEntity.setMessage(controlResult.getMessage());

        }else{
            updateEntity.setStatus(-1);
            riskCostRecordInfoService.saveOrUpdateCostRecordInfo(dateInfo, ReqActionEnum.FINISH, riskConfigInfo);
        }

        boolean update = this.updateById(updateEntity);
        if (!update){
            return null;
        }

        return this.getById(riskResultInfo.getId());
    }

    /**
     * 保存风控请求记录
     * @param riskBaseInfo
     * @param memberExtInfo
     * @return
     */
    private RiskResultInfo saveRiskResultInfo(RiskBaseInfo riskBaseInfo, MemberExtInfo memberExtInfo){
        RiskResultInfo riskResultInfo = new RiskResultInfo();
        riskResultInfo.setConfigId(riskBaseInfo.getConfigId());
        riskResultInfo.setDataId(String.valueOf(riskBaseInfo.getDataId()));
        riskResultInfo.setDataType(riskBaseInfo.getDataType());
        riskResultInfo.setDateInfo(LocalDate.now().toString());

        riskResultInfo.setUid(memberExtInfo.getUid());
        riskResultInfo.setUsername(memberExtInfo.getUsername());
        riskResultInfo.setMobile(memberExtInfo.getMobile());
        riskResultInfo.setIdcard(memberExtInfo.getIdCard());

        boolean save = this.save(riskResultInfo);
        if (!save){
            return null;
        }
        return this.getById(riskResultInfo.getId());
    }


    private RiskControlResult getRiskResult(JSONObject dataObject){

        RiskControlResult controlResult = new RiskControlResult();
        controlResult.setSuccess(false);

        String code = dataObject.getString("code");
        String desc = dataObject.getString("desc");
        if (!StrUtil.equals(code, "0")){
            controlResult.setMessage(desc);
            return controlResult;
        }

        JSONObject result_detail = dataObject.getJSONObject("result_detail");
        if (ObjectUtil.isEmpty(result_detail)){
            controlResult.setMessage("result_detail 对象为空");
            return controlResult;
        }

        JSONObject behaviorReportDetail = result_detail.getJSONObject("behavior_report_detail");
        if (ObjectUtil.isEmpty(behaviorReportDetail)){
            controlResult.setMessage("behavior_report_detail 对象为空");
            return controlResult;
        }

        // B22170040 近1个月履约贷款总金额
        String repayAmount = behaviorReportDetail.getString("B22170040");
        if (valueListSelf.contains(repayAmount)){
            controlResult.setMessage("近1个月履约贷款总金额不符合："+repayAmount);
            return controlResult;
        }

        /**
         * 近6 个月MI+逾期贷款笔数
         */
        String numberSettle = behaviorReportDetail.getString("B22170028");
        if (Integer.valueOf(numberSettle) > 1){
            controlResult.setMessage("近6 个月MI+逾期贷款笔数："+numberSettle);
            return controlResult;
        }

        controlResult.setSuccess(true);
        controlResult.setMessage("风控通过");
        return controlResult;

    }

    private List<String> valueListSelf = Arrays.asList("0", "(0,500)", "[500,1000)");



}
